package com.toolsder.demo.spring.security.jwt.service.impl;

import com.toolsder.demo.spring.security.jwt.config.util.JwtTokenUtil;
import com.toolsder.demo.spring.security.jwt.entity.MyUserDetails;
import com.toolsder.demo.spring.security.jwt.entity.UserInfo;
import com.toolsder.demo.spring.security.jwt.entity.database.Resources;
import com.toolsder.demo.spring.security.jwt.entity.database.Role;
import com.toolsder.demo.spring.security.jwt.entity.database.User;
import com.toolsder.demo.spring.security.jwt.exception.DefinedException;
import com.toolsder.demo.spring.security.jwt.repository.ResourcesRepository;
import com.toolsder.demo.spring.security.jwt.repository.RoleRepository;
import com.toolsder.demo.spring.security.jwt.repository.UserRepository;
import com.toolsder.demo.spring.security.jwt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * created by 猴子请来的逗比 On 2020/8/11
 *
 * @author by 猴子请来的逗比
 */
@Service
@Transactional(rollbackOn = Exception.class)
public class UserServiceImpl implements UserService {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private UserRepository userRepository;

    @Resource
    private ResourcesRepository resourcesRepository;

    /**
     * 获取用户
     *
     * @param username
     * @return
     */
    @Override
    public UserDetails loadUserByUsername(String username) {
        //获取
        User user = this.findByUserName(username);
        if (null == user) throw new DefinedException("用户在系統中不存在");
        MyUserDetails myUserDetails = new MyUserDetails();
        myUserDetails.setUsername(username);
        myUserDetails.setPassword(user.getPassword());
        //获取权限
        Set<Role> gjg2Roles = user.getRoles();
        List<String> roles = new ArrayList<>();
        for (Role role : gjg2Roles) {
            roles.add(role.getRoleCode());
        }
        //角色是一个特殊的权限，ROLE_前缀
        roles = roles.stream()
                .map(rc -> "ROLE_" + rc)
                .collect(Collectors.toList());
        //加载资源
        Set<String> authorties = new HashSet<>();
        for (Role role : gjg2Roles) {
            Set<Resources> scbz2Resources = role.getResources();
            scbz2Resources.forEach(in -> authorties.add(in.getResourcesUrl()));
        }
        authorties.addAll(roles);
        myUserDetails.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",", authorties)));
        return myUserDetails;
    }

    /**
     * 登录认证换取JWT令牌
     *
     * @param username
     * @param password
     * @return JWT
     */
    @Override
    public String login(String username, String password) {
        try {
            UsernamePasswordAuthenticationToken upToken =
                    new UsernamePasswordAuthenticationToken(username, password);
            Authentication authentication = authenticationManager.authenticate(upToken);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (AuthenticationException e) {
            throw new DefinedException("用户名或密码错误");
        }
        User user = this.findByUserName(username);
        if (null == user) throw new DefinedException("用户在系統中不存在");
        return jwtTokenUtil.generateToken(username);
    }

    /**
     * 通过token获取用户
     *
     * @param token
     * @return
     */
    @Override
    public User tokenToUser(String token) {
        String phoneNumber = jwtTokenUtil.getUsernameFromToken(token);
        if (null == phoneNumber) throw new DefinedException("token中用户名丢失");
        return this.findByUserName(phoneNumber);
    }


    /**
     * 获取用户信息
     */
    @Override
    public UserInfo getUserInfo(String token) {
        UserInfo userInfo = new UserInfo();

        return userInfo;
    }

    /**
     * 修改用户密码
     *
     * @param token
     * @param oldPassword
     * @param password
     */
    @Override
    public void modifyPassword(String token, String oldPassword, String password) {

        if (!StringUtils.isEmpty(token)) {
            User user = this.tokenToUser(token);
            if (passwordEncoder.matches(oldPassword, user.getPassword())) {
                user.setPassword(passwordEncoder.encode(password));
                userRepository.save(user);
            } else {
                throw new DefinedException("旧密码输入错误");
            }
        }
    }


    /**
     * 依据手机号获取用户
     *
     * @param username
     * @return
     */

    private User findByUserName(String username) {
        return userRepository.findByUsername(username);
    }
}
